﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace myLittleC
{
    using TSyntaxNodes = List<SyntaxNode>;
    /// <summary>
    /// общий клас, ля всех синтаксический конструкций
    /// </summary>
    abstract class SyntaxNode
    {
        public virtual SymType ExType
        {
            get { return null; }
            set { throw new NotImplementedException(); }
        }

        abstract public String ToString(String Shift);
        public virtual SyntaxExpression Calculate(SyntaxIdentefier iden, SyntaxNumConst val) { return null; }
    }

    /// <summary>
    /// общий класс для всех синтаксический выражений
    /// </summary>
    //TODO: Избавиться везде от SyntaxExpression

    abstract class SyntaxExpression : SyntaxNode
    {
        public virtual bool isConst { get { return false; } }
        abstract public String ToString(String prev, bool up);
        SymType mType = null;

        public override SymType ExType
        {  
            set
            {
                if (mType != null)  throw new ComException(ERRORS.SecSetType);
                mType = value;
            }
            get { return mType; }
        }

        public virtual SubTokenType Operation
        {
            get { return SubTokenType.None;}
            protected set { throw new NotImplementedException(); }
        }

        public virtual SyntaxExpression Calculate() { return this; }
    }

    /// <summary>
    /// представление унарной операции
    /// </summary>
    class SyntaxUnaryOp : SyntaxExpression
    {
        public SyntaxExpression Argument { get; private set; }
        public bool Postfix { get; private set; }
        public override SubTokenType Operation { get; protected set; }

        public SyntaxUnaryOp(SubTokenType iOper, SyntaxExpression iArgument) : this(iOper, iArgument, false) { }
        public SyntaxUnaryOp(SubTokenType iOper, SyntaxExpression iArgument, bool iPostfix)
        {
            Operation = iOper;
            Argument = iArgument;
            Postfix = iPostfix;
        }

        public override bool isConst{   get { return Argument.isConst; }}

        public override SyntaxExpression Calculate()
        {
            Argument = Argument.Calculate();

            if (!Argument.isConst )
                return this;

            var argument = (Argument is SyntaxConstInt) ? (Argument as SyntaxConstInt).Value : ((SyntaxConstReal)Argument).Value;

            switch (Operation)
            {
                case SubTokenType.Add:
                    
                    return Argument is SyntaxConstInt
                           ? (SyntaxNumConst)new SyntaxConstInt((int)argument)
                           : new SyntaxConstReal(argument);
                case SubTokenType.Sub:
                    return Argument is SyntaxConstInt 
                           ? (SyntaxNumConst)new SyntaxConstInt((int)(argument * -1))
                           : new SyntaxConstReal(argument * -1);
                case SubTokenType.Not:
                    return new SyntaxConstInt(argument == 0);
                case SubTokenType.Increment:
                    return new SyntaxConstInt((int)argument + 1);
                case SubTokenType.Decrement:
                    return new SyntaxConstInt((int)argument - 1);
            }
            return null;
        }

        public override SyntaxExpression Calculate(SyntaxIdentefier iden, SyntaxNumConst val)
        {
            var arg = Argument.Calculate(iden, val);
            
            return new SyntaxUnaryOp(Operation, arg ?? Argument, Postfix).Calculate();
        }

        public override String ToString()
        {
            return String.Format((Postfix ? "{0}{1}" : "{1}{0}"),
                Argument.ToString(), Tokenizer.StringOperation(Operation), ExType.Name);               
        }
        override public String ToString(String Shift)
        {
            return Postfix ? String.Format("{1}{2}\n{0}", Argument.ToString(Shift), Shift, Tokenizer.StringOperation(Operation))
                : String.Format("{0}\n{1}{2}", Argument.ToString(Shift + " "), Shift, Tokenizer.StringOperation(Operation));
        }
        public override String ToString(String prev, bool up)
        {
            String PrevLeft = (prev == "") ? "  " : String.Format("{0}{1}     ", prev, (up ? " " : "│"));
            String PrevCenter = (prev == "") ? " " : String.Format("{0}{1}────", prev, (up ? "┌" : "└"));

            String Left = Postfix ? String.Format("{0}┌────[{1}]", PrevLeft, Tokenizer.StringOperation(Operation)) : Argument.ToString(PrevLeft, true);
            String ce = Postfix ? Argument.ToString(prev, up) : String.Format("{0}[{1}]", PrevCenter, Tokenizer.StringOperation(Operation));
            return String.Format("{0}\n{1}│\n{2}", Left, PrevLeft, ce);
        }


    }
    /// <summary>
    /// представление бинарной операции
    /// </summary>
    class SyntaxBinaryOp : SyntaxExpression
    {
        public override bool isConst    { get {   return Left.isConst && Right.isConst;} }

        public SyntaxExpression Left { get; private set; }
        public SyntaxExpression Right { get; private set; }
        public bool IsLeft { get; private set; }

        public override SubTokenType Operation { get; protected set; }

        public SyntaxBinaryOp(SubTokenType iOper, SyntaxExpression iLeft, SyntaxExpression iRight)
        {
            Operation = iOper;
            Left = iLeft;
            Right = iRight;
        }

        public SyntaxBinaryOp(SubTokenType iOper, SyntaxExpression iLeft, SyntaxExpression iRight, SymType iExpType)
            :this(iOper, iLeft, iRight)
        {   ExType = iExpType;}


        public override SyntaxExpression Calculate()
        {
            Left = Left.Calculate();
            Right = Right.Calculate();

            if (!Left.isConst || !Right.isConst)
                return this;

            var left = (Left is SyntaxConstInt) ? (int)(Left as SyntaxConstInt).obValue : (float)((SyntaxConstReal) Left).obValue;
            var right = (Right is SyntaxConstInt) ? (int)(Right as SyntaxConstInt).obValue : (float)((SyntaxConstReal) Right).obValue;

            if (Operation < SubTokenType.OperationsLogicalStart ||
                Operation > SubTokenType.OperationsLogicalEnd)
            {
                object val=null;
                switch (Operation)
                {
                    case SubTokenType.Add:
                        val = left + right;
                        break;
                    case SubTokenType.Sub:
                        val = left - right;
                        break;
                    case SubTokenType.Multiply:
                        val = left * right;
                        break;
                    case SubTokenType.Division:
                        val = left / right;
                        break;
                    case SubTokenType.Div:
                        val = left % right;
                        break;
                    default:
                        throw  new ComException(ERRORS.UnKnownOp);
                }
               
                return Left is SyntaxConstInt && Right is SyntaxConstInt
                           ? (SyntaxNumConst) new SyntaxConstInt((int) ((float) val))
                           : new SyntaxConstReal((float) val);
            }
            else
            {
                bool val = false;
                switch (Operation)
                {
                    case SubTokenType.Equal:
                        val = left == right;
                        break;
                    case SubTokenType.NotEqual:
                        val = left != right;
                        break;
                    case SubTokenType.Hi:
                        val = left > right;
                        break;
                    case SubTokenType.Low:
                        val = left < right;
                        break;
                    case SubTokenType.HiOrEq:
                        val = left >= right;
                        break;
                    case SubTokenType.LowOrEq:
                        val = left <= right;
                        break;
                }
                return new SyntaxConstInt(val);
            }
        }

        public override SyntaxExpression Calculate(SyntaxIdentefier iden, SyntaxNumConst val)
        {
            var left = Left.Calculate(iden, val);
            var right = Right.Calculate(iden, val);
            
            return new SyntaxBinaryOp(Operation,  left ?? Left, right ?? Right).Calculate();
        }

        public override String ToString()
        { return String.Format("{0} {1} {2}", Left, Tokenizer.StringOperation(Operation), Right); }
        public override String ToString(String shift)
        { return String.Format("{0}\n{1}{2}\n{3}", Left.ToString(shift + " "), shift, Tokenizer.StringOperation(Operation), Right.ToString(shift + " ")); }

        public override String ToString(String prev, bool up)
        {
            String prevLeft, prevRight, prevCenter;
            if (prev == "")
            {
                prevCenter = " ";
                prevRight = prevLeft = "  ";
            }
            else
            {
                prevLeft = String.Format("{0}{1}     ", prev, (up ? " " : "│"));
                prevRight = String.Format("{0}{1}     ", prev, (up ? "│" : " "));
                prevCenter = String.Format("{0}{1}────", prev, (up ? "┌" : "└"));
            }

            String SLeft = Left.ToString(prevLeft, true);
            String SCenter = String.Format("{0}[{1}]", prevCenter, Tokenizer.StringOperation(Operation));
            String SRight = Right.ToString(prevRight, false);

            return String.Format("{0}\n{1}│\n{2}\n{3}│\n{4}", SLeft, prevLeft, SCenter, prevRight, SRight);
        }
    }

    class SyntaxDotOp : SyntaxBinaryOp
    {
        public SyntaxIdentefier Struct { get { return (SyntaxIdentefier)Left; } }
        public SyntaxExpression StructMember { get { return Right; } }

        public virtual SymStruct StructType { get { return (SymStruct)Struct.ExType; } }

        public SyntaxIdentefier StructMemberName
        {
             get    {   return  (StructMember is SyntaxIdentefier) ? StructMember as SyntaxIdentefier : ((SyntaxDotOp) StructMember).Struct;}
        }

        public SyntaxDotOp(SyntaxIdentefier iStruct, SyntaxExpression iStructMember, SubTokenType iType = SubTokenType.Dot)
            : base(iType, iStruct, iStructMember) { }
    }

    class SyntaxlArrowOp : SyntaxDotOp
    {
        public SyntaxlArrowOp(SyntaxIdentefier iStruct, SyntaxExpression iStructMember)
            : base(iStruct, iStructMember, SubTokenType.lArow) { }

        public override SymStruct StructType {   get{   return (SymStruct)((SymTypeLink)Struct.ExType).Type;} }
    }

    class SyntaxIndexArray : SyntaxExpression
    {
        public SyntaxExpression ArrayName;

        public List<SyntaxExpression> Indexes;

        public int Dimensions {get { return Indexes.Count(); }}

        public SymVarArray Vareble { get; set; }

        public SyntaxIndexArray(SyntaxExpression iArrayName, ref List<SyntaxExpression> iIndexes)
        {
            ArrayName = iArrayName;
            Indexes = iIndexes;
        }

        public override string ToString()
        {
            String sArgs = " ";

            foreach (SyntaxExpression index in Indexes)
                sArgs += index + ", ";

            return String.Format(" [|{0}| Args :{1} ] ", ArrayName.ToString(), sArgs);
        }

        public override String ToString(String prev, bool up)
        {
            String sArgs = " ";

            foreach (SyntaxExpression index in Indexes)
                sArgs += index + ", ";

            return String.Format("{0}|{1}| Args :{2}", ((prev == "") ? " " : String.Format("{0}{1}────", prev, (up ? "┌" : "└"))), ArrayName, sArgs);
        }

        public override String ToString(String Shift) {   return Shift;}
    }

    class SyntaxCallFunc : SyntaxExpression
    {
        public LinkedList<SyntaxExpression> Args { get; private set; }
        public String FunkName  { get; private set;}
        

        public SyntaxCallFunc(String iFunk, LinkedList<SyntaxExpression> iArgs, SymType t = null)
        {
            FunkName = iFunk;
            Args = iArgs;

            ExType = t;
        }

        public override sealed SymType ExType
        {
            get { return base.ExType; }
            set { base.ExType = value; }
        }

        public override SyntaxExpression Calculate(SyntaxIdentefier iden, SyntaxNumConst val)
        {
            LinkedList<SyntaxExpression> newArgs = new LinkedList<SyntaxExpression>();

            foreach (var arg in newArgs)
            {
                newArgs.AddLast(arg.Calculate(iden, val));
            }

            return new SyntaxCallFunc(FunkName, newArgs, ExType);
        }

        public override string  ToString()
        {
            String SArgs = " ";
            if (Args.Count != 0)
                SArgs = Args.Aggregate(SArgs, (current, arg) => current + (arg.ToString() + ", "));
            else
                SArgs += "Not Args";

            return String.Format(" [|{0}| Args :{1} ] ", FunkName, SArgs); 
        }
        
        public override String ToString(String prev, bool up) 
        {
            String SArgs = " ";
            if (Args.Count != 0)
                SArgs = Args.Aggregate(SArgs, (current, arg) => current + (arg.ToString() + ", "));
            else
                SArgs += "Not Args";

            return String.Format("{0}|{1}| Args :{2}", ((prev == "") ? " " : String.Format("{0}{1}────", prev, (up ? "┌" : "└"))), FunkName, SArgs); 
        }
        public override String ToString(String Shift){  return Shift;}
    }

    class SyntaxConst : SyntaxExpression
    {
        public override bool isConst { get { return true; } }
        public SubTokenType Type { get; private set; }
        
        /// <summary>
        /// возращает значение в типе обчекст, для обжности интерфейса
        /// </summary>
        public Object obValue { get; private set; }

        protected SyntaxConst(Object iValue, SubTokenType iType) { obValue = iValue; Type = iType; }
        protected SyntaxConst(Token iToken) { Type = iToken.SubType; obValue = iToken.Value; }

        public override String ToString() { return obValue.ToString(); }
        public override String ToString(String shift) { return shift + obValue; }

        public override String ToString(String prev, bool up)
        { return String.Format("{0}|{1}|", ((prev == "") ? " " : String.Format("{0}{1}────", prev, (up ? "┌" : "└"))), obValue); }
    }
    
    class SyntaxNumConst : SyntaxConst
    {
        protected SyntaxNumConst(Object iValue, SubTokenType iType) :base(iValue, iType){}
        protected SyntaxNumConst(Token iToken)  :base(iToken){}
    }
    
    /// <summary>
    /// реализация целочисленныйх коснстат
    /// </summary>
    class SyntaxConstInt :  SyntaxNumConst
    {
        public Int32 Value { get { return (Int32) obValue; }}

        public SyntaxConstInt(bool iValue) : base(iValue ? 1 : 0, SubTokenType.CttInt) { }

        public SyntaxConstInt(Int32 iValue) : base(iValue, SubTokenType.CttInt) { }
        public SyntaxConstInt(Token iToken) : base(iToken) { }

    }

    class SyntaxConstReal : SyntaxNumConst
    {
        public float Value { get { return (float) obValue; }}

        public SyntaxConstReal(float iValue): base(iValue, SubTokenType.CttFloat){}
        public SyntaxConstReal(Token iToken): base(iToken){}

        unsafe public override String ToString()
        {
            float t = Value;
            float* yy = &t;

            int* pointer = (int*)yy;

            return (*pointer).ToString();
        }
    }

    class SyntaxConstString : SyntaxConst
    {
        public String Value { get { return (string)obValue; } }

        public SyntaxConstString(String iValue): base(iValue, SubTokenType.CttStr){}
        public SyntaxConstString(Token iToken) : base(iToken) {}

        public override String ToString() { return Value;}
    }

    /// <summary>
    /// реализация идентефикатора
    /// </summary>
    class SyntaxIdentefier : SyntaxExpression
    {
        public String Name { get; private set; }

        public bool IsGlobal { get; set; }

        public SyntaxIdentefier(String iName):this(iName, false) {}
        public SyntaxIdentefier(String iName, bool iGlobal) 
        { 
            Name = iName;
            IsGlobal = iGlobal;
        }

        public override SyntaxExpression Calculate(SyntaxIdentefier iden, SyntaxNumConst val)
        {
            return Name == iden.Name ? val : null;
        }

        public override String ToString() { return " " + Name.ToString(); }
        public override String ToString(String Shift) { return Shift + Name.ToString(); }

        public override String ToString(String prev, bool up)
        { return String.Format("{0}|{1}|", ((prev == "") ? " " : String.Format("{0}{1}────", prev, (up ? "┌" : "└"))), Name); }
    };

    /// <summary>
    /// класс реализующий блок
    /// </summary>
    class SyntaxBlock : SyntaxNode
    {
        SymFunc mFunk = null;
        public bool FunkBody { get { return mFunk != null; } }

        public SyntaxBlock() : this(null) { }
        public SyntaxBlock(SyntaxBlock iParrent)
        {
            SyntaxNodes = new TSyntaxNodes();
            Table = new SymbolTable();
            Parrent = iParrent;
        }

        public SyntaxBlock(SyntaxBlock iParrent, ref SymFunc iFunk) : this(iParrent)
        {   mFunk = iFunk;}

        public void Add(SyntaxNode iS) { SyntaxNodes.Add(iS); }
        public ISymbol Add(ISymbol iS) { return Table.Add(iS); }

        public void EndDefentions() { _startExp = true; }
        public bool HaveNodes { get { return SyntaxNodes.Count != 0; } }

        public ISymbol Find(String iName) { return Table.Find(iName); }
        //public SymType ISymbol FindType(String iName) { return Table.FindType(iName); }
        public SymType FindType(String iName) { return Table.FindType(iName); }

        public ISymbol FindWithParent(String iName) { return Find(iName) ?? (Parrent != null ? Parrent.FindWithParent(iName) : null); }
        public ISymbol FindTypeWithParent(String iName) { return Table.FindType(iName) ?? (Parrent != null ? Parrent.FindTypeWithParent(iName) : null); }

        public bool HaveFunk(String iName) { return Table.FindFunc(iName) != null; }
        
        public String ToString(String prev, bool up) { return " "; }

        public override String ToString(String Shift) { return ToString(Shift, ""); }
        public String ToString(String Shift, String Name) 
        {
            return String.Format("\n{3}{0}:\n"+
                                  "{1}\n" +
                                  "{2}\n" +
                                  "{4}\n" +
                                  "{3}\n" +
                                  "{3}END BLOK\n",
                                 (Name != "" ? Name : "New Blok"),
                                Table.ToString(Shift),
                                WriteIncludedBlocks(Shift + Symbol.OneShift), 
                                Shift,
                                WriteExpresionsInBlock(Shift + Symbol.OneShift));
        }

        private String WriteExpresionsInBlock(String shift)
        {
            String res = "";
            foreach (SyntaxNode Node in SyntaxNodes)
                if (Node is SyntaxExpression) //TODO: Привести в порядок
                    res += shift + Node.ToString() + " " + (Node as SyntaxExpression).ExType.Name + '\n';
                else if (Node is SyntaxOperators)
                    res += shift + Node.ToString(shift + Symbol.OneShift) + '\n';
                    
            return res;
        }

        private String WriteIncludedBlocks(String shift)
        {
            return SyntaxNodes.OfType<SyntaxBlock>().Aggregate("", (current, Node) => current + Node.ToString(shift));
        }

        public String WriteTable(String shift, String name)
        {
            return String.Format("\n{3}{0}:\n{1}\n{2}\n{3}END BLOK\n",
                                   (name != "" ? name : "New Blok"),
                                  Table.ToString(shift), WriteIncludedTable(shift + Symbol.OneShift), shift);
        }

        public override String ToString() {   return ToString("", "");}

        private String WriteIncludedTable(String shift)
        {
            return SyntaxNodes.OfType<SyntaxBlock>().Aggregate("", (current, Node) => current + (Node).WriteTable(shift, ""));
        }

        //Propertis
        public bool MayDefs { get { return !_startExp; } }
        public bool MayExp { get { return _startExp; } }

        public SyntaxBlock Parrent { get; private set; }
        public SymbolTable Table { get; private set; }

        //private data
        bool _startExp;
        public TSyntaxNodes SyntaxNodes { get; private set; }

        public TSyntaxNodes Calc(SyntaxIdentefier iden, SyntaxNumConst val)
        {
            var nodes = new TSyntaxNodes(SyntaxNodes.Count);
            
            foreach (var node in SyntaxNodes)
                nodes.Add(node.Calculate(iden, val));
            
            return nodes;
        }

        public void Optimise()
        {
            foreach (var node in Table.Funks)
            {
                if(((SymFunc) node).Name != "printf")
                    ((SymFunc) node).Body.Optimise();
            }

            for (int i = 0; i < SyntaxNodes.Count; i++ )
            {
                if (SyntaxNodes[i] is SyntaxOperators)
                {
                    var nodes = ((SyntaxOperators)SyntaxNodes[i]).Optimise();

                    if (nodes != null)
                    {
                        SyntaxNodes.RemoveAt(i);
                        SyntaxNodes.InsertRange(i--, nodes);
                    }
                }
                else if (SyntaxNodes[i] is SyntaxBlock)
                {
                    ((SyntaxBlock) SyntaxNodes[i]).Optimise();
                }
            }

        }
    }

#region Операторы

    class SyntaxOperators : SyntaxNode
    {
        public SyntaxExpression Condition { get; protected set; }
        public SyntaxBlock Body { get; protected set; }

        public String Name { get; private set; }

       

        protected SyntaxOperators(SyntaxExpression iCondition, SyntaxBlock iBody, string iName = null)
        {
            Condition = iCondition;
            Body = iBody;
            Name = iName;
        }

        public override String ToString() { return ToString(""); }

        public override String ToString(String Shift)
        {
            return String.Format("Operator: {3}\n{0}Condition:\n\n{1}\n\n{0}Body:\n{2}\n{0}End Operator",
                Shift, Condition.ToString(Shift + Symbol.OneShift), Body.ToString(Shift + Symbol.OneShift), Name);
        }

        public virtual TSyntaxNodes Optimise(){   return null;}
    }

    class SyntaxWhile : SyntaxOperators
    {
        public SyntaxWhile(SyntaxExpression iCondition, SyntaxBlock iBody) : base(iCondition, iBody, "While"){}

        public override TSyntaxNodes Optimise()
        {
            Body.Optimise();
            if (!Condition.isConst)
                return null;
            return ((SyntaxConstInt)Condition).Value == 0 ? new TSyntaxNodes() : null;
        }
    }

    class SyntaxDoWhile : SyntaxOperators
    {
        public SyntaxDoWhile(SyntaxExpression iCondition, SyntaxBlock iBody) : base(iCondition, iBody, "DoWhile"){}

        public override TSyntaxNodes Optimise()
        {
            Body.Optimise();

            if (!Condition.isConst)
                return null;

            return ((SyntaxConstInt)Condition).Value == 0 ? Body.SyntaxNodes : null;
        }
    }

    class SyntaxFor : SyntaxOperators
    {
        public SyntaxExpression Initialization { get; private set; }
        public bool HaveInitialization { get { return Initialization != null; } }

        private SyntaxNumConst GetIteration(SyntaxNumConst startVal)
        {
            return Iteration.Calculate(CounterName, startVal) as SyntaxNumConst;
        }

        public SyntaxIdentefier CounterName
        {
            get
            {
                if (!(Initialization is SyntaxBinaryOp))
                    throw  new ComException((ERRORS.BadInitialization));

                var left = (Initialization as SyntaxBinaryOp).Left as SyntaxIdentefier;
                
                if (left  == null)
                    throw new ComException((ERRORS.BadInitialization));
        
                return left;
            }
        }

        public SyntaxNumConst CounterStartVal
        {
            get
            {
                if (!(Initialization is SyntaxBinaryOp))
                    throw new ComException((ERRORS.BadInitialization));

                var right = (Initialization as SyntaxBinaryOp).Right as SyntaxNumConst;

                if (right == null)
                    throw new ComException((ERRORS.BadInitialization));

                return right;
            }
        }

        public SyntaxExpression Iteration { get; private set; }
        public bool HaveIteration { get { return Iteration != null; } }

        public bool HaveCondition { get { return Condition != null; } }

        public SyntaxFor(IList<SyntaxExpression> iHead, SyntaxBlock iBody) : base(iHead[1], iBody, "For")
        {
            Initialization = iHead[0];
            Iteration = iHead[2];
        }

        private bool LimCountRepet()
        {
            return (Condition is SyntaxBinaryOp)
            && (Condition as SyntaxBinaryOp).Left is SyntaxIdentefier
            && (Condition as SyntaxBinaryOp).Right is SyntaxConst

            && (Initialization is SyntaxBinaryOp)
            && (Initialization as SyntaxBinaryOp).Left is SyntaxIdentefier
            && (Initialization as SyntaxBinaryOp).Right is SyntaxConst

            && ((Initialization as SyntaxBinaryOp).Left as SyntaxIdentefier).Name
                == ((Condition as SyntaxBinaryOp).Left as SyntaxIdentefier).Name
            && (Iteration is SyntaxUnaryOp)
            && ((Iteration as SyntaxUnaryOp).Operation == SubTokenType.Increment
                || (Iteration as SyntaxUnaryOp).Operation == SubTokenType.Decrement)
            ;
        }

        private int RepetCount()
        {
            if (LimCountRepet())
            {
                var t = new SyntaxBinaryOp(SubTokenType.Sub, ((SyntaxBinaryOp) Initialization).Right,
                                           ((SyntaxBinaryOp) Condition).Right);
                return Math.Abs(((SyntaxConstInt) t.Calculate()).Value);
            }
            return -1;
        }

        private TSyntaxNodes CalckWithShift(int shift)
        {
            var t = new TSyntaxNodes(Body.SyntaxNodes.Count);

            /*for(int i =0; i<Body.SyntaxNodes.Count; i++)
            {
                Body.SyntaxNodes[i]
            }*/
            return t;
        }

        public TSyntaxNodes BodyOptimise()
        {
            if (LimCountRepet())
            {
                if (RepetCount() < 5 && Body.SyntaxNodes.Count < 4)
                {
                    var t = new TSyntaxNodes();
                }
            }
            return null;
        }

        public override TSyntaxNodes Optimise()
        {
            Body.Optimise();
            if (Condition.isConst)
                return ((SyntaxConstInt)Condition).Value == 0 ? new TSyntaxNodes() : null;

         //   if(((SyntaxConstInt)(Condition.Calculate(CounterName, GetIteration(CounterStartVal)))).Value == 0)
         //       return Body.Calc(CounterName, GetIteration(CounterStartVal));

            if (Initialization is SyntaxBinaryOp 
                && (Initialization as SyntaxBinaryOp).Right.isConst
                && (Initialization as SyntaxBinaryOp).Left is SyntaxIdentefier)
            {
                var left = (Initialization as SyntaxBinaryOp).Left;
                var right = (Initialization as SyntaxBinaryOp).Right;

                var con = Condition.Calculate(left as SyntaxIdentefier, right as SyntaxNumConst);

                if (con.isConst && ((SyntaxConstInt)con).Value == 0)
                    return new TSyntaxNodes();


                  if(((SyntaxConstInt)(Condition.Calculate(CounterName, GetIteration(CounterStartVal)))).Value == 0)
                     return Body.Calc(CounterName, GetIteration(CounterStartVal));
            }

            return null;
        }

        public override String ToString(String shift)
        {
            return String.Format("Operator: For\n{0}Initialization:\n\n{5}{3}\n\n{0}Condition:\n\n{5}{1}\n\n{0}"
                                   + "{0}Initialization:\n\n{5}{4}\n\n{0}Body:\n{2}\n{0}End Operator",
                                   shift, Condition != null ? Condition.ToString() : " ", Body.ToString(shift + Symbol.OneShift),
                                   Initialization != null ? Initialization.ToString() : "",
                                   Iteration != null ? Iteration.ToString() : "", shift + Symbol.OneShift);
        }
    }

    class SyntaxIf : SyntaxOperators
    {
        public SyntaxIf Next{ get; set; }
        public SyntaxIf Prev { get; private set; }
        
        public bool IsElse { get { return Condition == null; } }
        public bool IsElseIf { get { return Prev != null && Condition != null; } }
        public bool IsIf { get { return Condition != null && Prev == null; } }

        public SyntaxIf(SyntaxExpression iCondition, SyntaxBlock iBody, SyntaxIf iParent = null) : base(iCondition, iBody, "If")
        {   Prev = iParent;}

        //возращает 
        //нул  если все нормально
        //пустой список если убить
        //список если убить а код закинуть в блок
        public override TSyntaxNodes Optimise()
        {
            if (!IsElse && Condition.isConst)
            {
                if (((SyntaxConstInt) Condition).Value == 0)
                {
                    if (Next == null)
                        return new TSyntaxNodes();
                    
                    if (IsIf && Next.IsElse)
                        return Next.Body.SyntaxNodes;   

                    Condition = Next.Condition;
                    Body = Next.Body;

                    Next = Next.Next;
                    if (Next != null)
                        Next.Prev = this;
                    
                   return Optimise();
                }
                
                if (IsIf)
                    return Body.SyntaxNodes;
                    
                Condition = null;
                Next = null;
            }

            Body.Optimise();
            if (Next != null)
                Next.Optimise();

            return null;
        }

        public override String ToString(String shift)
        {
            var head = Condition == null
                              ? "Else \n\n"
                              : String.Format("{0} If\n{1}Condition:\n\n{2}{3}\n\n",
                                              Prev != null ? "Else" : "Operator:", shift, shift + Symbol.OneShift, Condition);
            return String.Format(head + "{0}Body:\n{2}\n{0}{3}\n{0}End Operator",
                  shift, shift + Symbol.OneShift, Body.ToString(shift + Symbol.OneShift), (Next == null ? "" : Next.ToString(shift + Symbol.OneShift)));
        }
    }

    class SyntaxReturn : SyntaxOperators
    {
        public SyntaxExpression RetValue { get; private set; }

        public SyntaxReturn(SyntaxExpression iExp):base(null, null) {   RetValue = iExp;}

        public override String ToString(String shift){   return String.Format("return - {0}", RetValue.ToString());}

        public override TSyntaxNodes Optimise(){   return null;}
    }
#endregion
}

